package it.unibo.refolding.common;

import it.unimi.dsi.fastutil.doubles.Double2IntSortedMap;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.common.base.Function;

public class PointFrequencyFunctionInput {

    private static final Logger logger = Logger.getLogger(PointFrequencyFunctionInput.class.getSimpleName());
    
	public final double x;
	public final Double2IntSortedMap sortedMap;

	public PointFrequencyFunctionInput(double x, Double2IntSortedMap sortedMap) {
		this.x = x;
		this.sortedMap = sortedMap;
	}

	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
	}

	public static void right(
		double[] deflection, boolean[] potentialPeaks, WindowFrequencyFunctionInput fi,
		Function<PointFrequencyFunctionInput, Boolean> f) {
		if (fi.from != 0  && potentialPeaks[fi.from - 1]) {
			PointFrequencyFunctionInput input = new PointFrequencyFunctionInput(deflection[fi.from - 1], fi.sortedMap);
			potentialPeaks[fi.from - 1] = f.apply(input);
		}
		// The tail is unaffected.
	}

	public static void left(
		double[] deflection, boolean[] potentialPeaks, WindowFrequencyFunctionInput fi,
		Function<PointFrequencyFunctionInput, Boolean> f) {
		if (fi.to != deflection.length && potentialPeaks[fi.to]) {
			PointFrequencyFunctionInput input = new PointFrequencyFunctionInput(deflection[fi.to], fi.sortedMap);
			potentialPeaks[fi.to] = f.apply(input);
		}
		// The head is unaffected.
	}

	public static void center(
		double[] deflection, boolean[] indicator, WindowFrequencyFunctionInput fi,
		Function<PointFrequencyFunctionInput, Boolean> f) {
		int center = (fi.from + fi.to) / 2;
		if (indicator[center]) {
			PointFrequencyFunctionInput input = new PointFrequencyFunctionInput(deflection[center], fi.sortedMap);
			Boolean ok = f.apply(input);
			if (!ok) {
				logger.log(
					Level.FINER, "Rejecting peak {0} because of input={1}.",
					new Object[] {center, input});
			}
			indicator[center] = ok;
		}
		// The ends are unaffected.
	}
}